package model.io;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import model.algorithm.AbstractAlgorithm;
import model.algorithm.AbstractSurfaceIterator;
import model.algorithm.BestFitAlgorithm;
import model.algorithm.LowestFitAlgorithm;
import model.algorithm.PartitionedSteppingIterator;
import model.algorithm.SteppingSurface2DIterator;

import org.ini4j.Ini;
import org.ini4j.InvalidFileFormatException;

import util.Util;

public class IniReader {
	
	private Ini ini;
	
	private String[] algorithms;
	private String[] iterators;
	private int[] partitionWidths;
	private int[] lookaheads;
	private int[] lookaheadTypes;
	private int[] fieldWidths;
	private int[] blockamount;
	private String blockfile;
	private int timeout;
	
	public IniReader( String fileName ){
		ini = new Ini();
		try {
			ini.load(new File( fileName ));
		} catch (InvalidFileFormatException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		setStringAlgorithms();
		setStringIterators();
		
		setFieldWidths();
		setPartitionWidths();
		
		setLookAheads();
		setLookAheadTypes();
		setBlockAmount();
		setBlockFile();
		setTimeout();
	}
	
	private void setStringAlgorithms() {
		String algorithmsStr = ini.get( "algorithm", "algorithms" );
		algorithms = algorithmsStr.split( "," );
	}
	
	private void setStringIterators() {
		String iteratorsStr = ini.get(  "iterator", "iterators" );
		iterators = iteratorsStr.split( "," );
	}
	
	/**
	 * Returns a list with iterators, based on the fieldWidth provided
	 * 
	 * @param fieldWidth - width of the field
	 * @return list with iterators
	 */
	public List<AbstractSurfaceIterator> getIterators( int fieldWidth ) {
		List<AbstractSurfaceIterator> iteratorList = new ArrayList<AbstractSurfaceIterator>();
		
		for( int i=0; i < iterators.length; i++ ){
			
			if( iterators[i].trim().equalsIgnoreCase( "stepping" ) ){
				iteratorList.add(new SteppingSurface2DIterator());
			} else if( iterators[i].trim().equalsIgnoreCase( "partitioned" ) ){
				
				/* make an stepping iterator for every partitionwidth */
				for( int iPartitions=0; iPartitions < partitionWidths.length; iPartitions++ ){
					iteratorList.add( new PartitionedSteppingIterator(fieldWidth, partitionWidths[ iPartitions ]) );
				}
			}
		}
		
		return iteratorList;
	}
	
	/**
	 * Returns a list with algorithms based on the iterator provided
	 * 
	 * @param iterator
	 * @return list with algorithms
	 */
	public List<AbstractAlgorithm> getAlgorithms( List<AbstractSurfaceIterator> iterators ) {
		List<AbstractAlgorithm> algorithmList = new ArrayList<AbstractAlgorithm>();
		
		for( int i=0; i < algorithms.length; i++ ){
			
			for (AbstractSurfaceIterator iterator : iterators) {
				
				if( algorithms[i].trim().equalsIgnoreCase( "bestfit" ) ){
					algorithmList.add(new BestFitAlgorithm(iterator));
				} else if( algorithms[i].trim().equalsIgnoreCase( "lowestfit" ) ){
					algorithmList.add(new LowestFitAlgorithm(iterator));
				}
			}
		}
		
		return algorithmList;
	}
	
	private void setPartitionWidths(){
		String partitionWidthsStr = ini.get(  "iterator", "partitionwidths" );
		partitionWidths = intArrayFromString( partitionWidthsStr );
	}
	
	private void setLookAheads(){
		String lookaheadsStr = ini.get( "lookahead", "lookaheads" );
		lookaheads = intArrayFromString( lookaheadsStr );
	}
	
	private void setLookAheadTypes(){
		String lookaheadTypesStr = ini.get( "lookahead", "lookaheadtypes" );
		String[] splittedString = lookaheadTypesStr.split( "," );
		
		lookaheadTypes = new int[ splittedString.length ];
		
		for( int i=0; i < splittedString.length; i++ ){
			
			if( splittedString[i].trim().equalsIgnoreCase( "placeone" ) ){
				lookaheadTypes[i] = AbstractAlgorithm.LOOKAHEAD_PLACEONE;
			} else if( splittedString[i].trim().equalsIgnoreCase( "placeall" ) ){
				lookaheadTypes[i] = AbstractAlgorithm.LOOKAHEAD_PLACEALL;
			}
		}
	}
	
	private int[] intArrayFromString( String inputString ){
		return Util.intArrayFromString( inputString, "," );
	}
	
	/**
	 * Set field widths
	 */
	private void setFieldWidths(){
		String fieldwidths = ini.get( "field", "fieldwidth" );
		fieldWidths = intArrayFromString( fieldwidths );
	}
	

	/**
	 * Sets block amount
	 */
	private void setBlockAmount(){
		String blockamounts = ini.get( "blocks", "blockamount" );
		blockamount = intArrayFromString( blockamounts );
	}
	
	/**
	 * Sets blockfile
	 */
	private void setBlockFile(){
		blockfile = ini.get( "blocks", "blockfile" ).trim();
	}
	
	/**
	 * Sets timeout
	 */
	private void setTimeout(){
		try{
			timeout = Integer.parseInt( ini.get( "time", "timeout" ).trim() );
		} catch(NumberFormatException e){
			System.err.println( "Timeout should be an int, dimwit!" );
		}
	}
	

	/**
	 * @return the number of algorithms
	 */
	public int getNumberOfAlgorithms() {
		return algorithms.length;
	}

	public String[] getIterators() {
		return iterators;
	}
	
	/**
	 * @return the number of iterators
	 */
	public int getNumberOfIterators() {
		return iterators.length;
	}

	/**
	 * @return the lookaheads
	 */
	public int[] getLookaheads() {
		return lookaheads;
	}

	/**
	 * @return the lookaheadTypes
	 */
	public int[] getLookaheadTypes() {
		return lookaheadTypes;
	}

	/**
	 * @return the fieldWidths
	 */
	public int[] getFieldWidths() {
		return fieldWidths;
	}

	/**
	 * @return the blockamount
	 */
	public int[] getBlockamount() {
		return blockamount;
	}

	/**
	 * @return the blockfile
	 */
	public String getBlockfile() {
		return blockfile;
	}

	/**
	 * @return the timeout
	 */
	public int getTimeout() {
		return timeout;
	}
	
	/**
	 * @return the number of partitionWidths
	 */
	public int getNumberOfPartitionWidths() {
		return partitionWidths.length;
	}

}
